package com.columboid.testharness.util;

import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.Marshaller;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.columboid.protocol.syncml.metainfo.MetInf;
import com.columboid.protocol.syncml.representation.Cred;
import com.columboid.protocol.syncml.representation.Key;
import com.columboid.protocol.syncml.representation.ObjectFactory;
import com.columboid.protocol.syncml.representation.Routing;
import com.columboid.protocol.syncml.representation.Source;
import com.columboid.protocol.syncml.representation.Status;
import com.columboid.protocol.syncml.representation.SyncBody;
import com.columboid.protocol.syncml.representation.SyncHdr;
import com.columboid.protocol.syncml.representation.SyncML;
import com.columboid.protocol.syncml.representation.Target;
import com.columboid.protocol.syncml.representation.Ver;
import com.columboid.testharness.main.Authentication;
import com.columboid.testharness.main.ClientAuthentication;

public class SyncMLHandler {

	public SyncMLHandler() {
	}

	public static String generateXMLString(SyncML sml) {
		try {
			JAXBContext jaxbContext = JAXBContext
					.newInstance(new Class[] { ObjectFactory.class });
			Marshaller marshaller = jaxbContext.createMarshaller();
			java.io.StringWriter sw = new StringWriter();

			StreamResult result = new StreamResult();
			result.setWriter(sw);

			marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
					new Boolean(true));
			marshaller.marshal(sml, result);

			return sw.toString();

		} catch (JAXBException e) {
			e.printStackTrace();
			Log4j.logger.error(e.toString());
			return "";
		}

	}

	public static SyncML CreateSymcMLObject(StringReader xmlReader,
			StringReader xsdReader) throws JAXBException, SAXException {
		JAXBContext jaxbContext = JAXBContext
				.newInstance(new Class[] { ObjectFactory.class });

		SchemaFactory sf = SchemaFactory
				.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);

		Schema schema = sf.newSchema(new SAXSource(new InputSource(xsdReader)));

		Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
		unmarshaller.setSchema(schema);

		StreamSource source = new StreamSource(xmlReader);
		JAXBElement<SyncML> smlElement = (JAXBElement<SyncML>) unmarshaller
				.unmarshal(source, SyncML.class);
		SyncML sml = (SyncML) smlElement.getValue();
		return sml;
	}

	public static SyncML CreateSymcMLObject(String MsgID, String SessionID,
			String Username, String Password, String Token, String PublicKey,
			String NextNonce) {
		Source src = new Source();
		src.setLocURI(MacAddress.getMacAddress());
		src.setLocName(Username);

		// set header
		SyncHdr shdr = new SyncHdr();
		shdr.setMsgID(MsgID);
		shdr.setVerDTD(SYNCHDR_VERDTD);
		shdr.setVerProto(SYNCHDR_VERPROTO);
		shdr.setSessionID(SessionID);
		Target target = new Target();
		target.setLocURI(TARGET_LOCURI);
		shdr.setSource(src);

		// set cred
		if ((Password != null && Token != null) || NextNonce != null) {
			Cred cred = new Cred();
			cred.setMeta(MetInfHandler.CreateMetInfObjectStr(NextNonce));

			if ((Password != null && Token != null)) {
				Authentication Auth = new ClientAuthentication();
				String HashedPass = Auth.getMd5Base64Password(Password);
				cred.setData(Auth.getMd5Base64Password(Username + HashedPass
						+ Token));
			} else
				cred.setData("");
			shdr.setCred(cred);
		}
		shdr.setTarget(target);

		// set body

		Routing rt = new Routing();
		Ver ver = new Ver();
		ver.setSupportVersion(SYNCHDR_VERDTD);
		rt.setVer(ver);
		rt.setLang("en-US");
		rt.setDevice("PC");
		SyncBody sbdy = new SyncBody();
		sbdy.getKeyOrRoutingOrAlert().add(rt);
		// set key
		if (PublicKey != null) {
			Key key = new Key();
			key.setCmdID("1");
			key.setData(PublicKey);
			sbdy.getKeyOrRoutingOrAlert().add(key);
		}
		SyncML sml = new SyncML();
		sml.setSyncHdr(shdr);
		sml.setSyncBody(sbdy);
		return sml;
	}

	public static String CreateSymcMLObjectString(String MsgID,
			String SessionID, String Username, String Password, String Token,
			String PublicKey, String NextNonce) {
		return generateXMLString(CreateSymcMLObject(MsgID, SessionID, Username,
				Password, Token, PublicKey, NextNonce));
	}

	public static String getNextNonce(SyncML sml) {

		Status st = (Status) sml.getSyncBody().getKeyOrRoutingOrAlert().get(0);
		return MetInfHandler.getToken(st.getChal().getMeta());

	}

	public static String getStatus(SyncML sml) {
		Status st = (Status) sml.getSyncBody().getKeyOrRoutingOrAlert().get(0);
		return st.getData();
	}

	public static String getCredData(SyncML sml) {
		return sml.getSyncHdr().getCred().getData();
	}

	public static boolean checkCred(String Cred, String Username,
			String Password, String Token) {
		boolean re = false;

		Authentication Auth = new ClientAuthentication();
		String HashedPass = Auth.getMd5Base64Password(Password);
		if (Cred.equals(Auth
				.getMd5Base64Password(Username + HashedPass + Token)))
			re = true;
		return re;
	}

	private final static String TARGET_LOCURI = "http://www.columboid.com/Service";
	private final static String SYNCHDR_VERDTD = "1.1";
	private final static String SYNCHDR_VERPROTO = "SyncML/1.1";
}
